using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PDOGenerator.MapTypes;
using PDOGenerator.DbToMoreGen;
using System.Collections.ObjectModel;

using System.Xml.Serialization;
using System.Xml;
using System.IO;

using PDOGenerator.Util;

namespace PDOGenerator.MapTypes
{
    public class Project
    {

        internal static Project CurrentSerial;
        public Project()
        {
            CurrentSerial = this;
        }

        public Database Database
        {
            get
            {
                return DataTypeMap.Databases[DBType];
            }
        }

        private string _DBType = "SQLServer";
        [Category("Connection")]
        public string DBType
        {
            get { return _DBType; }
            set { _DBType = value; }
        }

        private string _ConnectionString = "Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI;";
        [Category("Connection")]
        public string ConnectionString
        {
            get { return _ConnectionString; }
            set { _ConnectionString = value; }
        }

        private string _ProjectName;
        [Category("Project")]
        public string ProjectName
        {
            get { return _ProjectName; }
            set { _ProjectName = value; }
        }

        private string _FileName;
        [Category("Project")]
        public string FileName
        {
            get { return _FileName; }
            set { _FileName = value; }
        }

        private string _storedProcPrefix;
        [Category("Project")]
        public string StoredProcPrefix
        {
            get { return _storedProcPrefix; }
            set { _storedProcPrefix = value; }
        }

        private string _defaultSchemaName = "dbo";
        [Category("Project")]
        public string DefaultSchemaName
        {
            get { return _defaultSchemaName; }
            set { _defaultSchemaName = value; }
        }

        private string _usingDirectives;
        [Category("Project")]
        public string UsingDirectives
        {
            get { return _usingDirectives; }
            set { _usingDirectives = value; }
        }

        private string _baseClassName;
        [Category("Project")]
        public string BaseClassName
        {
            get { return _baseClassName; }
            set { _baseClassName = value; }
        }



        private string _OutputDirectory;
        public string OutputDirectory
        {
            get { return _OutputDirectory; }
            set { _OutputDirectory = value; }
        }

        private string _scriptOutputDirectory;
        public string ScriptOutputDirectory
        {
            get { return _scriptOutputDirectory; }
            set { _scriptOutputDirectory = value; }
        }

        private string _SubDir;
        public string SubDir
        {
            get { return _SubDir; }
            set { _SubDir = value; }
        }


        private string _NameSpace;
        public string NameSpace
        {
            get { return _NameSpace; }
            set { _NameSpace = value; }
        }

        private string _Assembly;
        public string Assembly
        {
            get { return _Assembly; }
            set { _Assembly = value; }
        }

        private bool _targetAzure;
        public bool TargetAzure
        {
            get { return _targetAzure; }
            set { _targetAzure = value; }
        }

        private bool _generateTableCreateScripts;
        public bool GenerateTableCreateScripts
        {
            get { return _generateTableCreateScripts; }
            set { _generateTableCreateScripts = value; }
        }

        private bool _generateTableDropScripts;
        public bool GenerateTableDropScripts
        {
            get { return _generateTableDropScripts; }
            set { _generateTableDropScripts = value; }
        }

        private bool _generateDataInsertScripts;
        public bool GenerateDataInsertScripts
        {
            get { return _generateDataInsertScripts; }
            set { _generateDataInsertScripts = value; }
        }

        private bool _generateProcScripts;
        public bool GenerateProcScripts
        {
            get { return _generateProcScripts; }
            set { _generateProcScripts = value; }
        }

        private bool _generateClassFiles;
        public bool GenerateClassFiles
        {
            get { return _generateClassFiles; }
            set { _generateClassFiles = value; }
        }



        private SerialDictionary<string, SchemaMap> _Schemas = new SerialDictionary<string, SchemaMap>();

        /// <summary>
        /// Database schemas.  Each schema contains corresponding table dictionary.
        /// </summary>
        [Browsable(false)]
        public SerialDictionary<string, SchemaMap> Schemas
        {
            get { return _Schemas; }
            set { _Schemas = value; }
        }

        [XmlIgnore]
        public List<SchemaMap> SchemaList
        {
            get { return _Schemas.Values.ToList<SchemaMap>(); }
        }


        private SerialDictionary<string, TableMap> _AllTables = new SerialDictionary<string, TableMap>();

        /// <summary>
        /// Complete table dictionary.  
        /// Useful for tracking foreign key references; not the way to go when interested in schema organization.
        /// When dealing with schema, go through the Schemas.Tables dictionary.
        /// </summary>
        [Browsable(false)]
        public SerialDictionary<string, TableMap> AllTables
        {
            get { return _AllTables; }
            set { _AllTables = value; }
        }

        [XmlIgnore]
        public List<TableMap> AllTableList
        {
            get { return _AllTables.Values.ToList<TableMap>(); }
        }



        public void Save()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Project));

            // Create an XmlTextWriter using a FileStream.
            Stream fs = new FileStream(FileName, FileMode.Create);
            XmlWriterSettings Settings = new XmlWriterSettings();
            Settings.Indent = true;
            Settings.NewLineHandling = NewLineHandling.Entitize;
            XmlWriter writer = XmlWriter.Create(fs, Settings);

            // Serialize using the XmlTextWriter.
            serializer.Serialize(writer, this);

            writer.Close();
            fs.Close();
        }

        public static Project Load(string FileName)
        {
            // Create an instance of the XmlSerializer specifying type and namespace.
            XmlSerializer serializer = new XmlSerializer(typeof(Project));

            // A FileStream is needed to read the XML document.
            FileStream fs = new FileStream(FileName, FileMode.Open);
            XmlReaderSettings Settings = new XmlReaderSettings();
            Settings.IgnoreWhitespace = true;
            Settings.IgnoreComments = true;
            XmlReader reader = XmlReader.Create(fs, Settings);


            Project p = null;

            try
            {
                // Use the Deserialize method to restore the object's state.
                p = (Project)serializer.Deserialize(reader);
            }
            finally
            {
                reader.Close();
                fs.Close();
            }

            SyncSchemaProjectTables(p);

            return p;
        }


        /// <summary>
        /// Synchronize Schema table dictionary and Project table dictionary.
        /// </summary>
        /// <param name="p">Project</param>
        public static void SyncSchemaProjectTables(Project p)
        {
            
            // Clear all tables from schemas
            foreach (SchemaMap s in p.SchemaList)
            {
                s.Tables.Clear();
                s.IsPresentInDatabase = false;
            }

            //p.Schemas.Clear();

            // Copy from project tables into schema tables
            foreach (TableMap t in p.AllTableList)
            {
                SchemaMap s;
                if (!p.Schemas.ContainsKey(t.SchemaName))
                {
                    s = new SchemaMap(p);
                    s.SchemaName = t.SchemaName;

                    p.Schemas.Add(t.SchemaName, s);
                    s.IsPresentInDatabase = true; // need to mark new schemas as present
                }
                else
                {
                    s = p.Schemas[t.SchemaName];
                    s.IsPresentInDatabase = true;
                }

                s.Tables.Add(t.TableMoniker, t);
            }

            // Clean out any dead schemas
            List<string> deadSchemaList = new List<string>();
            foreach (SchemaMap s in p.Schemas.Values)
            {
                if (s.IsPresentInDatabase == false)
                {
                    deadSchemaList.Add(s.SchemaName);
                }
            }

            foreach (string sn in deadSchemaList)
            {
                p.Schemas.Remove(sn);
            }
        }


        public override string ToString()
        {
            return ProjectName;
        }
    }
}
